package tools

import (
	"bufio"
	"fmt"
	"github.com/groob/plist"
	"image"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"unplist/controllers"
)

var control controllers.ImageControl
var big_image image.Image
// 输入输出目录默认值
var _inPath = "in"
var _outPath = "out"

//调用os.MkdirAll递归创建文件夹
func CreateMutiDir(filePath string) error {
	if !isExist(filePath) {
		err := os.MkdirAll(filePath, os.ModePerm)
		if err != nil {
			//fmt.Println("创建文件夹失败,error info:", err)
			return err
		}
		return err
	}
	return nil
}

// 判断所给路径文件/文件夹是否存在(返回true是存在)
func isExist(path string) bool {
	_, err := os.Stat(path) //os.Stat获取文件信息
	if err != nil {
		if os.IsExist(err) {
			return true
		}
		return false
	}
	return true
}



// 解压入口
func UnPlist(inPath string, outPath string) {
	_inPath = inPath
	_outPath = outPath
	control = controllers.ImageControl{}
	xfiles, _ := GetAllFiles(inPath)
	for _, file := range xfiles {
		//fmt.Printf("获取的文件为[%s]\n", file)
		pngPath := strings.Replace(file, ".plist", ".png", 1)
		plistToPng(pngPath, file)
	}
}

func plistToPng(pngPath string, plistPath string) {
	if !isExist(pngPath) || !isExist(plistPath) {
		return
	}
	src, err := control.LoadImage(pngPath)
	if err != nil {
		log.Println("load image fail..")
	}
	big_image = src

	f, err := os.Open(plistPath)
	if err != nil {
		//fmt.Println(err)
		os.Exit(2)
	}
	defer f.Close()
	bufReader := bufio.NewReader(f)
	var sparseBundleHeader interface{}
	d := plist.NewXMLDecoder(bufReader)
	err = d.Decode(&sparseBundleHeader)
	if err != nil {
		fmt.Println(err)
	}
	////fmt.Println(sparseBundleHeader)
	root := sparseBundleHeader.(map[string]interface{})
	for key, value := range root {
		////fmt.Println(key,":",value)
		if key == "frames" {
			frames := value.(map[string]interface{})
			for k, v := range frames {
				//fmt.Println(k, ":", v)
				gen_png_from_plist(k, v.(map[string]interface{}), plistPath)
			}
		}
	}
}

//获取指定目录下的所有文件,包含子目录下的文件
func GetAllFiles(dirPth string) (files []string, err error) {
	var dirs []string
	dir, err := ioutil.ReadDir(dirPth)
	if err != nil {
		return nil, err
	}

	PthSep := string(os.PathSeparator)
	//suffix = strings.ToUpper(suffix) //忽略后缀匹配的大小写

	for _, fi := range dir {
		if fi.IsDir() { // 目录, 递归遍历
			dirs = append(dirs, dirPth+PthSep+fi.Name())
			GetAllFiles(dirPth + PthSep + fi.Name())
		} else {
			// 过滤指定格式
			ok := strings.HasSuffix(fi.Name(), ".plist")
			if ok {
				files = append(files, dirPth+PthSep+fi.Name())
			}
		}
	}

	// 读取子目录下文件
	for _, table := range dirs {
		temp, _ := GetAllFiles(table)
		for _, temp1 := range temp {
			files = append(files, temp1)
		}
	}

	return files, nil
}

// 拆成小图
func gen_png_from_plist(k string, v map[string]interface{}, plistPath string) {
	var spriteSourceSize []int
	if value, ok := v["spriteSourceSize"]; ok {
		spriteSourceSize = to_list(value.(string))
	} else if value, ok := v["sourceSize"]; ok {
		spriteSourceSize = to_list(value.(string))
	} else {
		str := "{" + ConvertInterfaceToString(v["width"]) + "," + ConvertInterfaceToString(v["height"]) + "}"
		spriteSourceSize = to_list(str)
	}

	var textureRect []int
	if value, ok := v["textureRect"]; ok {
		textureRect = to_list(value.(string))
		//fmt.Println(textureRect)
	} else if value, ok := v["frame"]; ok {
		textureRect = to_list(value.(string))
		//fmt.Println(textureRect)
	} else {
		str := "{{" + ConvertInterfaceToString(v["x"]) + "," + ConvertInterfaceToString(v["y"]) + "},{" + ConvertInterfaceToString(v["width"]) + "," + ConvertInterfaceToString(v["height"]) + "}}"
		textureRect = to_list(str)
	}
	var isRotate bool
	//var e error
	if value, ok := v["textureRotated"]; ok {
		isRotate, _ = value.(bool)
		//fmt.Println(isRotate)
	} else if value, ok := v["rotated"]; ok {
		isRotate, _ = value.(bool)
		//fmt.Println(isRotate)
	} else {
		isRotate = false
	}

	var spriteOffset []int
	if value, ok := v["spriteOffset"]; ok {
		spriteOffset = to_list(value.(string))
	} else if value, ok := v["offset"]; ok {
		spriteOffset = to_list(value.(string))
	} else if _, ok := v["offsetX"]; ok {
		str := "{" + ConvertInterfaceToString(v["offsetX"]) + "," + ConvertInterfaceToString(v["offsetY"]) + "}"
		spriteOffset = to_list(str)
	} else {
		str := "{0,0}"
		spriteOffset = to_list(str)
	}
	var x int
	var y int
	var width int
	var height int
	x = textureRect[0]
	y = textureRect[1]
	if isRotate {
		width = textureRect[3]
		height = textureRect[2]
	} else {
		width = textureRect[2]
		height = textureRect[3]
	}
	box := []int{textureRect[0], textureRect[1], width, height}

	img1, err := control.ImageCopy(big_image, x, y, box[2], box[3])
	if err != nil {
		log.Println("image copy fail...")
		return
	}
	var img image.Image
	var sWidth, sHeight int

	sWidth = spriteSourceSize[0]
	sHeight = spriteSourceSize[1]
	if isRotate {
		img = control.Rotate270(img1)
	} else {
		img = img1
	}
	var result_box []int
	if isRotate {
		result_box = []int{
			int((spriteSourceSize[0]-height)/2 + spriteOffset[0]),
			int((spriteSourceSize[1]-width)/2 - spriteOffset[1]),
			int((spriteSourceSize[0]+height)/2 + spriteOffset[0]),
			int((spriteSourceSize[1]+width)/2 - spriteOffset[1]),
		}

	} else {
		result_box = []int{
			int((spriteSourceSize[0]-width)/2 + spriteOffset[0]),
			int((spriteSourceSize[1]-height)/2 - spriteOffset[1]),
			int((spriteSourceSize[0]+width)/2 + spriteOffset[0]),
			int((spriteSourceSize[1]+height)/2 - spriteOffset[1]),
		}
	}
	//fmt.Println(sWidth, sHeight)
	var result_image image.Image
	if result_box[0] != 0 || result_box[1] != 0 {
		//按照偏移重新出图
		result_image = control.Paste(img, image.Rect(0, 0, sWidth, sHeight), image.Pt(result_box[0], result_box[1]))
	} else {
		result_image = img
	}
	plistDir := filepath.Dir(plistPath) // 取出plist 的路径
	imgName := plistDir + "/" + k
	kDir := filepath.Dir(imgName)
	outDir := strings.Replace(kDir, _inPath, _outPath, 1)
	// 判断输出目录是否存在不存在则创建
	err = CreateMutiDir(outDir)
	if err != nil {
		fmt.Printf("CreateMutiDir fail err:%s\n", err)
	}
	outFile := outDir + "/" + filepath.Base(k)

	saveErr := control.SaveImage(outFile, result_image)
	if saveErr != nil {
		log.Println("save image fail..")
	}
}

func to_list(str string) []int {
	s1 := strings.Replace(str, "{", "", -1)
	s2 := strings.Replace(s1, "}", "", -1)
	arr := strings.Split(s2, ",")
	arrNum := make([]int, 0)
	for i := 0; i < len(arr); i++ {
		num, _ := strconv.Atoi(arr[i])
		arrNum = append(arrNum, num)
	}
	return arrNum
}

func ConvertInterfaceToString(t interface{}) string {
	switch t.(type) {
	case nil:
		return ""
	case int:
		return strconv.Itoa(t.(int))
	case float64:
		return strconv.Itoa(int(t.(float64)))
	case string:
		return t.(string)
	case uint64:
		return strconv.Itoa(int(t.(uint64)))
	default:
		return ""
	}
}


